package com.jhf.youke.base.domain.service;


import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.jhf.youke.base.domain.converter.MenuConverter;
import com.jhf.youke.base.domain.gateway.MenuRepository;
import com.jhf.youke.base.domain.model.Do.MenuDo;
import com.jhf.youke.base.domain.model.po.MenuPo;
import com.jhf.youke.base.domain.model.vo.MenuVo;
import com.jhf.youke.base.domain.model.vo.RouterVo;
import com.jhf.youke.core.common.localChace.LocalCache;
import com.jhf.youke.core.ddd.AbstractDomainService;
import com.jhf.youke.core.entity.PageQuery;
import com.jhf.youke.core.entity.Pagination;
import com.jhf.youke.core.utils.Constant;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author RHJ
 */
@Service
@Log4j2
public class MenuService extends AbstractDomainService<MenuRepository, MenuDo, MenuVo> {


    @Resource
    MenuConverter menuConverter;

    @Override
    public boolean update(MenuDo entity) {
        MenuPo menuPo = menuConverter.do2Po(entity);
        menuPo.preUpdate();
        return repository.update(menuPo);
    }

    @Override
    public boolean updateBatch(List<MenuDo> doList) {
        List<MenuPo> poList = menuConverter.do2PoList(doList);
        return repository.updateBatch(poList);
    }

    @Override
    public boolean delete(MenuDo entity) {
        MenuPo menuPo = menuConverter.do2Po(entity);
        return repository.delete(menuPo);
    }

    @Override
    public boolean deleteBatch(List<Long> idList) {
        return repository.deleteBatch(idList);
    }

    @Override
    public boolean insert(MenuDo entity) {
        MenuPo menuPo = menuConverter.do2Po(entity);
        menuPo.preInsert();
        return repository.insert(menuPo);
    }

    @Override
    public boolean insertBatch(List<MenuDo> doList) {
        List<MenuPo> poList = menuConverter.do2PoList(doList);
        MenuPo.getInsertListId(poList);
        return repository.insertBatch(poList);
    }

    @Override
    public Optional<MenuVo> findById(Long id) {
        Optional<MenuPo> menuPo =  repository.findById(id);
        MenuVo menuVo = menuConverter.po2Vo(menuPo.orElse(new MenuPo()));
        return Optional.ofNullable(menuVo);

    }

    @Override
    public boolean remove(Long id) {
        return repository.remove(id);
    }

    @Override
    public boolean removeBatch(List<Long> idList) {
        return repository.removeBatch(idList);
    }

    @Override
    public List<MenuVo> findAllMatching(MenuDo entity) {
        MenuPo menuPo = menuConverter.do2Po(entity);
        List<MenuPo>menuPoList =  repository.findAllMatching(menuPo);
        return menuConverter.po2VoList(menuPoList);
    }


    @Override
    public Pagination<MenuVo> selectPage(MenuDo entity){
        MenuPo menuPo = menuConverter.do2Po(entity);
        PageQuery<MenuPo> pageQuery = new PageQuery<>(menuPo,entity.getCurrentPage(), entity.getPageSize(), entity.getQuerySort());
        Pagination<MenuPo> pagination = repository.selectPage(pageQuery);
        return new Pagination<MenuVo>(pagination.getPageNum(),pagination.getPageSize(),pagination.getTotalSize(),
                menuConverter.po2VoList(pagination.getList()));
    }

    /**
    * @description:  菜单 list转树状结构算法
    * @param: [list]
    * @return: java.util.List<com.jhf.youke.base.domain.model.vo.MenuVo>
    * @author: RHJ
    * @Date: 2022/9/20
    */
    public List<MenuVo> getTree(List<MenuVo> list){
        Multimap<Long, MenuVo> mulMap = ArrayListMultimap.create();
        List<MenuVo> menuVoList = new ArrayList<>();
        for(MenuVo menuVo : list){
            mulMap.put(menuVo.getParentId(), menuVo);
        }
        Collection<MenuVo> menuVos = mulMap.get(0L);

        menuVos.forEach(menu -> {
            getSubTree(menu, mulMap);
            menuVoList.add(menu);
        });
        return menuVoList;
    }

    public MenuVo getSubTree(MenuVo menuVo, Multimap<Long, MenuVo> mulMap){

        Collection<MenuVo> menuVos = mulMap.get(menuVo.getId());
        menuVo.setSubMenus( new  ArrayList<>(menuVos));
        menuVos.forEach(menu -> getSubTree(menu, mulMap));
        return menuVo;
    }

    public List<MenuPo> getAllMenu(){
        QueryWrapper<MenuPo> qw = new QueryWrapper<>();
        qw.eq("del_flag","0");
        List<MenuPo> menuPoList = repository.list(qw);
        return menuPoList;
    }

    @SuppressWarnings("unchecked")
    public List<MenuPo> getAllMenuByCache(){
        String key = "all_menu";
        List<MenuPo> menuPoList = (List<MenuPo>) LocalCache.get(key);
        if(menuPoList == null){
            menuPoList = getAllMenu();
            LocalCache.put(key, menuPoList, 20 * 60 * 60);
        }
        return menuPoList;
    }

    public Map<Long,MenuPo> getAllMenuToMap(){
        List<MenuPo> menuPoList = getAllMenuByCache();
        return menuPoList.stream().collect(Collectors.toMap(MenuPo::getId, item -> item, (entity1, entity2) -> entity1));
    }



    /**
    * @Description:  1. 拿到所菜单集合
     *               2。 树状排序
     *               3。 转成前端所需结构
    * @Param: [menuIds]
    * @return: java.util.List<com.jhf.youke.base.domain.model.vo.RouterVo>
    * @Author: RHJ
    * @Date: 2022/11/3
    **/
    public List<RouterVo> getRouterList(Set<Long> menuIds,Long userId) {
        Map<Long, MenuPo> allMenuToMap = getAllMenuToMap();
        List<MenuPo> menuPoList = new ArrayList<>(256);
        // 如果超级管理员直接取所有菜单，否则根据权限拿
        if(Constant.SUPER_ADMINISTRATOR.equals(userId)){
            menuPoList = getAllMenuByCache();
        }else{
            for(Long id :menuIds){
                menuPoList.add(allMenuToMap.get(id));
            }
        }
        // 没有排序之前
        List<MenuVo> menuVos = menuConverter.po2VoList(menuPoList);
        // 树状排序
        List<MenuVo> menuVoList =  getTree(menuVos);
        log.info("menuVoList {}", JSONUtil.toJsonStr(menuVoList));
        return converterRouterList(menuVoList);
    }

    private List<RouterVo> converterRouterList(List<MenuVo> menuVoList) {
        List<RouterVo> routerVoList = new ArrayList<>();
        for (MenuVo menuVo : menuVoList){
            RouterVo routerVo = new RouterVo(menuVo);
            if (!menuVo.getSubMenus().isEmpty() && menuVo.getSubMenus().size() > 0 && menuVo.getType() == 0) {
                routerVo.setChildren(converterRouterList(menuVo.getSubMenus()));
            }
            routerVoList.add(routerVo);
        }
        return routerVoList;
    }

}

